package com.piece.admin.service;

import com.piece.admin.model.TbSysDict;
import com.piece.admin.repository.TbSysDictRepository;
import com.piece.core.framework.constant.ExceptionConstants;
import com.piece.core.framework.enums.OptionType;
import com.piece.core.framework.enums.StatusType;
import com.piece.core.framework.enums.sql.SqlKey;
import com.piece.core.framework.exception.ErrorCode;
import com.piece.core.framework.exception.FrameWorkException;
import com.piece.core.framework.util.collection.CollectionUtil;
import com.piece.core.framework.util.object.ObjectUtil;
import com.piece.core.jpa.repository.BaseService;
import com.piece.core.framework.support.bootstrap.Order;
import com.piece.core.framework.support.bootstrap.TreeData;
import com.piece.core.framework.support.convert.Convert;
import com.piece.core.framework.util.string.StringUtil;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.io.Serializable;
import java.util.*;

@Service
@Transactional
public class TbSysDictService extends BaseService<TbSysDict, Long> {

    @Resource
    private TbSysDictRepository tbSysDicRepository;

    @Resource
    private JdbcTemplate jdbcTemplate;

    @PostConstruct
    public void initRepository() {
        setRepository(tbSysDicRepository);
    }

    /**
     * 新增字典信息
     */
    @Override
    public TbSysDict insert(TbSysDict dict) {
        if (0 != dict.getParentCode()) {
            TbSysDict info = tbSysDicRepository.findById(dict.getParentCode());
            // 如果父节点不为"正常"状态,则不允许新增子节点
            if (!StatusType.NORMAL.getCode().equals(info.getStatus())) {
                throw new FrameWorkException(new ErrorCode(ExceptionConstants.NOT_EXIST, info.getDictLabel()));
            }
            if (StringUtil.isEmpty(info.getAncestors())) {
                dict.setAncestors(Convert.toStr(dict.getParentCode(), "0"));
            } else {
                dict.setAncestors(info.getAncestors() + "," + dict.getParentCode());
            }
        } else {
            dict.setAncestors(null);
        }
        return tbSysDicRepository.insert(dict);
    }

    /**
     * 更新字典信息
     */
    @Override
    public void update(TbSysDict dict) {
        TbSysDict info = tbSysDicRepository.findById(dict.getParentCode());
        if (null != info) {
            String ancestors = Convert.toStr(dict.getParentCode());
            if (StringUtil.isEmpty(info.getAncestors())) {
                if ("0".equals(ancestors)) {
                    ancestors = null;
                }
            } else {
                ancestors = info.getAncestors() + "," + info.getDictCode();
            }
            dict.setAncestors(ancestors);
            updateDictChildren(dict.getDictCode(), ancestors);
        }
        tbSysDicRepository.update(dict);
        if (StatusType.NORMAL.getCode().equals(dict.getStatus())) {
            updateDictParent(dict);
        }
    }

    /**
     * 修改父关系
     */
    private void updateDictParent(TbSysDict dict) {
        dict = tbSysDicRepository.findById(dict.getParentCode());
        if (null != dict) {
            dict.setStatus(StatusType.NORMAL.getCode());
            tbSysDicRepository.update(dict);
            updateDictParent(dict);
        }
    }

    /**
     * 修改子关系
     *
     * @param dictCode  字典ID
     * @param ancestors 祖级列表
     */
    public void updateDictChildren(Long dictCode, String ancestors) {
        ancestors = ancestors == null ? "" : (ancestors + ",");
        HashMap<String, Object> condition = new HashMap<>();
        condition.put("parentCode", dictCode);
        condition.put("status", StatusType.NORMAL.getCode());
        List<TbSysDict> children = tbSysDicRepository.findByCondition(condition, null);
        for (TbSysDict child : children) {
            child.setAncestors(ancestors + dictCode);
        }
        if (children.size() > 0) {
            tbSysDicRepository.batchUpdate(children);
        }
    }

    /**
     * 删除字典
     */
    @Override
    public void delete(Serializable dictCode) {
        tbSysDicRepository.updateByProperties("dictCode", (Long) dictCode, "status", StatusType.DELETE.getCode());
    }

    /**
     * 批量删除字典
     */
    @Override
    public int delete(Serializable[] ids) {
        List<Long> param_in = Arrays.asList((Long[]) ids);
        return tbSysDicRepository.updateByProperties("Q_dictCode_L_IN", param_in, "status", StatusType.DELETE.getCode());
    }

    /**
     * 查询字典组名数据
     */
    public List<TbSysDict> findDicGroup() {
        HashMap<String, Object> condition = new HashMap<>();
        condition.put("dictType", OptionType.GROUP.getCode());
        condition.put("status", StatusType.NORMAL.getCode());
        return tbSysDicRepository.findByCondition(condition, generateDefaultOrder());
    }

    /**
     * 根据字典组名查询字典选项
     *
     * @param dictGroup 字典组名
     * @return 字典选项集合信息
     */
    public List<TbSysDict> findByDicGroup(String dictGroup) {
        return findByDicGroup(dictGroup, true);
    }

    /**
     * 根据字典组名查询字典数据
     *
     * @param dictGroup 字典组名
     * @param onlyOption 是否只返回选项数据
     * @return 字典数据集合信息
     */
    public List<TbSysDict> findByDicGroup(String dictGroup, boolean onlyOption) {
        HashMap<String, Object> condition = new HashMap<>();
        condition.put("dictGroup", dictGroup);
        if (onlyOption) {
            condition.put("dictType", OptionType.OPTION.getCode());
        }
        condition.put("status", StatusType.NORMAL.getCode());
        return tbSysDicRepository.findByCondition(condition, generateDefaultOrder());
    }

    /**
     * 根据字典类型和字典键值查询字典数据信息
     *
     * @param dictGroup 字典组名
     * @param dictValue 字典键值
     */
    public TbSysDict findByGroupValue(String dictGroup, String dictValue) {
        HashMap<String, Object> condition = new HashMap<>();
        condition.put("dictGroup", dictGroup);
        condition.put("dictValue", dictValue);
        condition.put("status", StatusType.NORMAL.getCode());
        return tbSysDicRepository.findOneByCondition(condition);
    }

    /**
     * 根据字典类型和字典键值查询字典数据信息
     *
     * @param dictGroup 字典组名
     * @param dictValue 字典键值
     */
    public List<TbSysDict> findByGroupValue(String dictGroup, List<String> dictValue) {
        HashMap<String, Object> condition = new HashMap<>();
        condition.put("dictGroup", dictGroup);
        condition.put("Q_dictValue_S_IN", dictValue);
        condition.put("status", StatusType.NORMAL.getCode());
        return tbSysDicRepository.findByCondition(condition, generateDefaultOrder());
    }

    /**
     * 查询字典组列表
     */
    public List<TbSysDict> findByGroupValue(String dictGroup) {
        HashMap<String, Object> condition = new HashMap<>();
        condition.put("dictGroup", dictGroup);
        condition.put("dictType", OptionType.OPTION.getCode());
        condition.put("status", StatusType.NORMAL.getCode());
        return tbSysDicRepository.findByCondition(condition, generateDefaultOrder());
    }

    /**
     * 查询字典树
     */
    public List<TreeData> findTreeData(List<TbSysDict> dictList) {
        return findTreeData(dictList, false, null);
    }

    /**
     * 查询字典树
     */
    public List<TreeData> findTreeData(List<TbSysDict> dictList, boolean group) {
        return findTreeData(dictList, false, null, group);
    }

    /**
     * 对象转字典树
     *
     * @param dictList     字典列表
     * @param isCheck      是否需要选中
     * @param selectedList 已存在字典列表
     * @return
     */
    public List<TreeData> findTreeData(List<TbSysDict> dictList, boolean isCheck, List<String> selectedList) {
        return findTreeData(dictList, isCheck, selectedList, false);
    }

    /**
     * 对象转字典树
     *
     * @param dictList     字典列表
     * @param isCheck      是否需要选中
     * @param selectedList 已存在字典列表
     * @return
     */
    public List<TreeData> findTreeData(List<TbSysDict> dictList, boolean isCheck, List<String> selectedList, boolean group) {
        List<TreeData> trees = new ArrayList<>();
        boolean checked;
        for (TbSysDict dict : dictList) {
            TreeData treeData = TreeData.builder()
                    .id(String.valueOf(dict.getDictCode()))
                    .pId(String.valueOf(dict.getParentCode()))
                    .title(dict.getDictValue())
                    .name(dict.getDictLabel())
                    .build();

            if (isCheck) {
                if (group) {
                    checked = selectedList.contains(dict.getDictGroup());
                } else {
                    checked = selectedList.contains(dict.getDictCode().toString());
                }
                treeData.setChecked(checked);
            } else {
                treeData.setChecked(false);
            }
            trees.add(treeData);
        }
        return trees;
    }

    /**
     * 获取下一个字典序号
     *
     * @param dict
     */
    public Long findNextDictSort(TbSysDict dict) {
        String sql = "select ifnull(max(dict_sort) + 1,1) from tb_sys_dict where parent_code = " + dict.getParentCode();
        return jdbcTemplate.queryForObject(sql, Long.class);
    }

    public void validDict(String dictGroup, Collection<String> values) {
        if (ObjectUtil.isEmpty(values)) {
            return;
        }

        List<TbSysDict> dicts = findByGroupValue(dictGroup, new ArrayList<>(values));
        Map<String, TbSysDict> dictMap = CollectionUtil.convertMap(dicts, TbSysDict::getDictValue);
        values.forEach(value -> {
            TbSysDict dict = dictMap.get(value);
            if (null == dict) {
                throw new FrameWorkException(new ErrorCode(ExceptionConstants.NOT_EXIST, "字典值【" + value + "】"));
            }
            if (StatusType.NORMAL.getCode().equals(dict.getStatus())) {
                throw new FrameWorkException(new ErrorCode(ExceptionConstants.IS_DISABLE, dict.getDictLabel()));
            }
        });
    }

    protected List<Order> generateDefaultOrder() {
        List<Order> orders = new ArrayList<>();
        orders.add(new Order("dictSort", SqlKey.ASC));
        return orders;
    }
}
